#pragma once
#include "Command.hpp"
#include <functional>
#include <unordered_map>
#include <fstream>
#include <string>
#include"Log.hpp"

const std::string defaultDictPath = "./dictionary.txt";

class UdpServer
{
    private:
    std::string handleDict(std::string str)
    {
        if(_dict.count(str)==0)
        {
            return "NONE";
        }

        return str+":"+_dict[str];
    }
public:
    UdpServer(uint16_t port = gdefaultport) : _port(port),
                                              _isrunning(false)
    {
        // 加载本地内容
        std::ifstream file(defaultDictPath);

        std::string line;
        while (std::getline(file, line))
        {
            int n = line.find(" ");
            if (n == std::string::npos)
            {
                LOG(LogModule::LogLevel::WARNING) << "当前行读取错误:"<<line;
                continue;
            }
            _dict[line.substr(0,n)]=line.substr(n+1);
            // 避免读取与使用编码不一样
            //LOG(LogModule::LogLevel::WARNING) << "加载的内容为:"<<line.substr(0,n)<<"大小为："<<line.substr(0,n).size();
        }

        file.close();
    }

    void InitServer()
    {
        // 1. 创建socket
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            perror("socket error");
            return;
        }

        // 2. 填充网络信息，并bind绑定
        struct sockaddr_in serv_addr;
        serv_addr.sin_family = AF_INET; // 保持一致性
        serv_addr.sin_port = ::htons(_port);
        serv_addr.sin_addr.s_addr = ::htonl(INADDR_ANY);

        // 加载进入内核
        int n = bind(_sockfd, CONV(&serv_addr), sizeof(sockaddr_in));
        if (n == -1)
        {
            perror("bind error");
            return;
        }

        std::cout << "bind success IP:" << "port:" << _port << std::endl;
    }

    void Start()
    {
        if (_isrunning)
            return;

        _isrunning = true;
        std::cout << "Begining receive" << std::endl;
        // 服务器死循环接受数据
        while (true)
        {
            struct sockaddr_in client_addr;
            socklen_t addr_len = sizeof(client_addr);
            char buffer[1024];
            // 阻塞接受
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, CONV(&client_addr), &addr_len);
            if (n == -1)
            {
                perror("recvfrom error");
                continue;
            }
            buffer[n] = 0;

            std::string ip = ::inet_ntoa(client_addr.sin_addr);
            uint16_t port = ::ntohs(client_addr.sin_port);
            printf("from %s:%u:%s\n", ip.c_str(), port, buffer);

            // 回显
            std::string info = "echo #"+handleDict(buffer);
            ::sendto(_sockfd, info.c_str(), info.size(), 0, CONV(&client_addr), addr_len);
        }
    }
    ~UdpServer()
    {
        if (_isrunning)
            ::close(_sockfd);
    }

private:
    int _sockfd;
    uint16_t _port;  // 服务器未来的端口号
    bool _isrunning; // 服务器运行状态

    std::unordered_map<std::string, std::string> _dict;
};
